/* 
 * File:   Template.cpp
 * Author: H4314
 * 
 * Created on 24 avril 2012, 08:11
 */

#include "Template.h"

Template::Template(Element * templateElement)
        : templateElement(templateElement)
{
    list<Attribute *>::const_iterator itAttr;

    // On récupère l'attribut match            
    for(itAttr = templateElement->getAttributes().begin(); elementMatchedName.empty() && itAttr != templateElement->getAttributes().end(); itAttr++)
        if((*itAttr)->getName() == ATTR_MATCH)
            elementMatchedName = (*itAttr)->getValue();
    
    contentToDraw = new Content("\033[31m%" + elementMatchedName + "%\033[00m");
}

// Asssume contentToDraw & templateElement must be clean elsewhere
Template::~Template() {
    list<Node *>::const_iterator it;
    
    for(it = toClean.begin(); it != toClean.end(); it++)
    {
        Element * element = dynamic_cast<Element *>(*it);
        if(element != NULL)
            element->setChildren(list<Node*>());
    }
    Content::CleanItUp(toClean);
}

// Insère la liste de noeud à la place de APPLY_TEMPLATES ou VALUE_OF (récursif)
// insertNode renvoie un sous arbre de racine <template>
Node * Template::insertNode(Node * node, const list<Node *> & elementsToInsert) { 
    list<Node *>::const_iterator it;
    list<Attribute *>::const_iterator ita;
    Element * element = dynamic_cast<Element *>(node);
    
    // Le noeud existe
    if(node != NULL)
    {
        // Le noeud est un element
        if(element != NULL)
        {
            list<Node *> children;
            list<Attribute *> attributes;

            // On parcourt les enfants de l'élement courant node
            for(it = element->getChildren().begin(); it != element->getChildren().end(); it++)
            {
                Element * child = dynamic_cast<Element *>(*it);

                // Si l'element est un APPLY_TEMPLATE ou VALUE_OF
                if(child != NULL && child->getNameSpace() == NS_XSL && (child->getName() == APPLY_TEMPLATES || child->getName() == VALUE_OF))
                {
                    list<Node *>::const_iterator insert;

                    // On insère la liste de noeuds
                    for(insert = elementsToInsert.begin(); insert != elementsToInsert.end(); insert++)
                    {
                        children.push_back(*insert);
                    }
                }
                else
                    children.push_back(insertNode(*it, elementsToInsert));
            }
            
            // On copie les attributs
            for (ita = element->getAttributes().begin(); ita != element->getAttributes().end(); ita++)
                attributes.push_back(new Attribute(**ita));

            
            Element * newElement = new Element(element->getName(), element->getNameSpace(), children, attributes);
            return newElement;
        }
        // Le noeud est un content
        else
        {
            Content * content = dynamic_cast<Content *>(node);
            Content * newContent = new Content(content->getText());
            return newContent;
        }
    }
    return NULL;
}

// Applique le template à la liste de noeuds
// Apply se charge de couper la racine <template> et de renvoyer
// ses branches (enfants)
list<Node *> Template::Apply(const list<Node *> & nodesToInsert) {
    list<Node *>::const_iterator it;
    list<Node *> result;
    Node * node = insertNode(templateElement, nodesToInsert);
    
    if(node != NULL)
    {
        Element * element = dynamic_cast<Element *>(node);
        
        if(element != NULL)
        {
            for(it = element->getChildren().begin(); it != element->getChildren().end(); it++)
                result.push_back(*it);
        }
        else
            result.push_back(node);
    }
    
    toClean.push_back(node);
    
    return result;
}

const string & Template::getElementMatchedName() const {
    return elementMatchedName;
}

// Retourne la liste des templates customizés destiné à l'affichage
// Alias de "Apply(contentToDraw)"
list<Node *> Template::Draw() {
    return Apply(list<Node *>(1, (Node*) contentToDraw));
}